import { OnInit, Component, EventEmitter, Injector, Output, ViewChild } from '@angular/core';
import { AppComponentBase } from '@shared/common/app-component-base';
import { ListResultDtoOfMenuItemDto, MoveMenuItemInput, NavigationServiceProxy, MenuItemDto, MenuCleanServiceProxy, EntityDtoOfGuid } from '@shared/service-proxies/service-proxies';
import { filter as _filter, remove as _remove } from 'lodash-es';
import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { EditSortComponent } from './edit-sortnum-modal.component';

import { TreeNode, MenuItem } from 'primeng/api';

import { ArrayToTreeConverterService } from '@shared/utils/service/array-to-tree-converter.service';
import { TreeDataHelperService } from '@shared/utils/service/tree-data-helper.service';
import { MenuConfigModalComponent } from './menu-config-modal.component';
import { Tree } from 'primeng/tree';


@Component({
    selector: 'menu-tree',
    templateUrl: './menus-tree.component.html'
})
export class MenuTreeComponent extends AppComponentBase implements OnInit {

    @Output() addMenu = new EventEmitter<MenuItemDto>();
    @Output() editMenu = new EventEmitter<MenuItemDto>();

    @ViewChild('editSortNumModal', { static: true }) editSortNumModal: EditSortComponent;
    @ViewChild('menuConfigModal', { static: true }) menuConfigModal: MenuConfigModalComponent;
    @ViewChild('ptree', { static: true }) ptree: Tree;

    treeData: any;
    selectedOu: TreeNode;
    ouContextMenuItems: MenuItem[];
    canMoveMenuItem = false;
    saving = false;

    private fieldMappings = [
        {
            target: 'label',
            targetFunction(item) {
                return item.displayName;
            }
        }, {
            target: 'expandedIcon',
            targetFunction(item) {
                if (item.isActive) {
                    return 'fa fa-folder-open text-warning';
                } else {
                    return 'fa fa-folder-open font-grey';
                }
            }
        },
        {
            target: 'collapsedIcon',
            targetFunction(item) {
                if (item.isActive) {
                    return 'fa fa-folder text-warning';
                } else {
                    return 'fa fa-folder font-grey';
                }
            }
        },
        {
            target: 'selectable',
            value: true
        }
    ];

    constructor(
        injector: Injector,
        private _navigationService: NavigationServiceProxy,
        private _arrayToTreeConverterService: ArrayToTreeConverterService,
        private _treeDataHelperService: TreeDataHelperService
    ) {
        super(injector);
    }

    totalUnitCount = 0;

    ngOnInit(): void {
        this.canMoveMenuItem = this.isGranted('Pages.Tenant.Menus.Move');
        this.ouContextMenuItems = this.getContextMenuItems();
        this.getTreeDataFromServer();
    }

    nodeSelect(event) {
        this.editMenu.emit(<MenuItemDto>event.node.data);
    }

    isDroppingBetweenTwoNodes(event: any): boolean {
        return event.originalEvent.target.nodeName === 'LI';
    }

    _filter(value) {
        this.ptree._filter(value);
    }

    nodeDrop(event) {
        const input = new MoveMenuItemInput();
        input.id = event.dragNode.data.id;
        let dropNodeDisplayName = '';

        if (this.isDroppingBetweenTwoNodes(event)) {//between two item
            input.newParentId = event.dropNode.parent ? event.dropNode.parent.data.id : null;
            dropNodeDisplayName = event.dropNode.parent ? event.dropNode.parent.data.displayName : this.l('Root');
        } else {
            input.newParentId = event.dropNode.data.id;
            dropNodeDisplayName = event.dropNode.data.displayName;
        }

        this.message.confirm(
            this.l('OrganizationUnitMoveConfirmMessage', event.dragNode.data.displayName, dropNodeDisplayName),
            this.l('AreYouSure'),
            isConfirmed => {
                if (isConfirmed) {
                    this._navigationService.moveMenuItem(input)
                        .pipe(catchError(error => {
                            this.revertDragDrop();
                            return throwError(error);
                        }))
                        .subscribe(() => {
                            this.notify.success(this.l('SuccessfullyMoved'));
                            this.reload();
                        });
                } else {
                    this.revertDragDrop();
                }
            }
        );
    }


    reload(): void {
        this.getTreeDataFromServer();
    }

    private revertDragDrop() {
        this.reload();
    }

    private getTreeDataFromServer(): void {
        this._navigationService.getMenuTree().subscribe((result: ListResultDtoOfMenuItemDto) => {
            this.totalUnitCount = result.items.length;
            this.treeData = this._arrayToTreeConverterService.createTree(result.items,
                'parentId',
                'id',
                null,
                'children',
                this.fieldMappings,
                (a,b)=>a.order- b.order
                );
            this.addMenu.emit(null);
        });
    }


    private getContextMenuItems(): any[] {
        const permissions = {
            menusCreate: this.isGranted('Pages.Tenant.Menus.Create'),
            menusEdit: this.isGranted('Pages.Tenant.Menus.Edit'),
            menusDelete: this.isGranted('Pages.Tenant.Menus.Delete'),
            menusCopy: this.isGranted('Pages.Tenant.Menus.Copy')
        };

        let items = [
            {
                label: this.l('AddSubMenuItem'),
                disabled: !permissions.menusCreate,
                command: () => {
                    this.addMenu.emit(this.selectedOu.data);
                }
            },
            {
                label: this.l('Delete'),
                disabled: !permissions.menusDelete,
                command: () => {
                    this.message.confirm(
                        this.l('DeleteWarningMessage', this.selectedOu.data.displayName),
                        this.l('AreYouSure'),
                        isConfirmed => {
                            if (isConfirmed) {
                                this._navigationService.deleteMenuItem(this.selectedOu.data.id).subscribe(() => {
                                    this.deleteMenu(this.selectedOu.data.id);
                                    this.notify.success(this.l('SuccessfullyDeleted'));
                                    this.selectedOu = null;
                                    this.addMenu.emit(null);
                                });
                            }
                        }
                    );
                }
            },
            {
                label: this.l('Release'),
                disabled: !permissions.menusEdit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._navigationService.setActive(input).subscribe((result) => {
                        this.menuUpdated(result);
                        this.notify.success(this.l('ReleaseSuccessfully'));
                    });
                }
            },
            {
                label: this.l('CancelRelease'),
                disabled: !permissions.menusEdit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._navigationService.setInActive(input).subscribe((result) => {
                        this.menuUpdated(result);
                        this.notify.success(this.l('CancelReleaseSuccessfully'));
                    });
                }
            },
            {
                label: this.l('UpSort'),
                disabled: !permissions.menusEdit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._navigationService.upSort(input).subscribe(result => {
                        result.items.forEach(t => {
                            this.menuUpdated(t);
                        });

                        this.notify.success(this.l('OrderSuccessSuccessfully'));
                    });
                }
            },
            {
                label: this.l('DownSort'),
                disabled: !permissions.menusEdit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._navigationService.downSort(input).subscribe((result) => {
                        result.items.forEach(t => {
                            this.menuUpdated(t);
                        });
                        this.notify.success(this.l('OrderSuccessSuccessfully'));
                    });
                }
            },
            {
                label: this.l('ChangeSortNum'),
                disabled: !permissions.menusEdit,
                command: () => {
                    this.editSortNumModal.show(this.selectedOu.data);
                }
            },
            {
                label: this.l('Copy'),
                disabled: !permissions.menusCopy,
                command: () => {
                    this.message.confirm(
                        this.l('CopyWarningMessage', this.selectedOu.data.displayName),
                        this.l('AreYouSure'),
                        isConfirmed => {
                            if (isConfirmed) {
                                const input = new EntityDtoOfGuid({
                                    id: this.selectedOu.data.id
                                })
                                this._navigationService.copyMenu(input).subscribe((result) => {
                                    this.menuCreated(result);
                                    this.notify.success(this.l('CopySuccessfully'));
                                    this.selectedOu = null;
                                    this.editMenu.emit(result);
                                });
                            }
                        }
                    );
                }
            },
            {
                label: this.l('StyleAndScript'),
                disabled: false,
                command: () => {
                    this.menuConfigModal.show(this.selectedOu.data);
                }
            }
        ];


        return items;
    }

    menuCreated(ou: MenuItemDto): void {
        let newNode = {
            data: ou,
            children: [],
            selected: true
        };

        this._arrayToTreeConverterService.mapFields(ou, newNode, this.fieldMappings);

        if (ou.parentId) {
            let unit = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.parentId } });
            if (!unit) {
                return;
            }

            unit.children.push(newNode);

            if (unit.expanded !== true) {
                unit.expanded = true;
            }
        } else {
            this.treeData.push(newNode);
        }

        this.totalUnitCount += 1;
    }

    private deleteMenu(id) {
        let node = this._treeDataHelperService.findNode(this.treeData, { data: { id: id } });
        if (!node) {
            return;
        }

        if (!node.data.parentId) {
            _remove(this.treeData, {
                data: {
                    id: id
                }
            });
        }

        let parentNode = this._treeDataHelperService.findNode(this.treeData, { data: { id: node.data.parentId } });
        if (!parentNode) {
            return;
        }

        _remove(parentNode.children, {
            data: {
                id: id
            }
        });

        this.totalUnitCount -= 1;
    }

    menuUpdated(ou: MenuItemDto): void {
        let item = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.id } });
        if (!item) {
            return;
        }
        this._arrayToTreeConverterService.mapFields(ou, item, this.fieldMappings);
        item.data = ou;

        if (ou.parentId) {
            let parentitem = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.parentId } });
            if (!parentitem) {
                return;
            }
            parentitem.children = parentitem.children.sort((a, b) => a.data.order - b.data.order);
        }else{
            this.treeData = this.treeData.sort((a, b) => a.data.order - b.data.order);
        }
    }

    addRootMenu(): void {
        this.addMenu.emit(null);
    }

    expandAll() {
        this._treeDataHelperService.operateTreeNode(this.treeData, (t)=>t.expanded = true);
    }

    collapseAll() {
        this._treeDataHelperService.operateTreeNode(this.treeData, (t)=>t.expanded = false);
    }
}
